package lc.util;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;

import com.jme.renderer.ColorRGBA;

public final class Material {
	public String name;
	public int id;
	public ArrayList<Material> subMaterials;
	public Hashtable<String, ArrayList<Prop>> props = new Hashtable<String, ArrayList<Prop>>();
	public Hashtable<String, Prop> propsById = new Hashtable<String, Prop>();

	public Object clone() {
		Material m = new Material();
		m.id = id;
		m.name = name;
		Enumeration<String> keys = props.keys();
		while (keys.hasMoreElements()) {
			String key = keys.nextElement();
			ArrayList<Prop> plist = new ArrayList<Prop>();
			for (Prop p : props.get(key)) {
				p = (Prop)p.clone();
				plist.add(p);
				if (p.id != null)
					m.propsById.put(p.id, p);
			}
			m.props.put(key, plist);
		}
		return m;
	}

	public static final class Prop {
		private Prop() {
		}
		Prop(String name, Object obj) {
			this.name = name;
			this.value = obj;
			if (obj == null) {
				this.type = NULL;
			}
			else if (obj instanceof Float) {
				this.type = FLOAT;
			}
			else if (obj instanceof ColorRGBA) {
				this.type = COLOR;
			}
			else if (obj instanceof TextureMap) {
				this.type = TEXTURE;
			}
			else {
				this.type = OBJECT;
			}
		}
		public Prop(String name, float value) {
			this(name, (Object)value);
		}
		public Prop(String name, ColorRGBA value) {
			this(name, (Object)value);
		}
		public Prop(String name, TextureMap value) {
			this(name, (Object)value);
		}
		public Object clone() {
			Prop p = new Prop();
			p.name = name;
			p.id = id;
			p.type = type;
			p.value = value;
			return p;
		}
		public String name;
		public String id;
		public int type;
		public Object value;
		public static final int OBJECT = -1;
		public static final int NULL = 0;
		public static final int FLOAT = 1;
		public static final int COLOR = 2;
		public static final int TEXTURE = 3;
	}

	public final Material getMaterial(int id) {
		if (subMaterials == null || subMaterials.size() == 0)
			return this;
		return subMaterials.get(id % subMaterials.size());
	}

	public ArrayList<Prop> property(String name) {
		return props.get(name.toLowerCase());
	}

	public Prop property(String name, int type, Object dflt) {
		name = name.toLowerCase();
		ArrayList<Prop> ps = property(name);
		if (ps == null)
			return new Prop(name, dflt);
		for (Prop p : ps)
			if (p.type == type)
				return p;
		return new Prop(name, dflt);
	}

	public Prop propertyById(String name) {
		return propsById.get(name);
	}

	public float propertyFloat(String name, float dflt) {
		ArrayList<Prop> list = property(name.toLowerCase());
		if (list == null)
			return dflt;
		for (Prop p : list)
			if (p.type == Prop.FLOAT)
				return (float)(Float)p.value;
		return dflt;
	}

	public ColorRGBA propertyColor(String name, ColorRGBA dflt) {
		ArrayList<Prop> list = property(name.toLowerCase());
		if (list == null)
			return dflt;
		for (Prop p : list)
			if (p.type == Prop.COLOR)
				return (ColorRGBA)p.value;
		return dflt;
	}

	public ColorRGBA propertyCombinedColor(String name, ColorRGBA dflt) {
		ColorRGBA ret = new ColorRGBA(1, 1, 1, 1);
		float scale = 1;
		ArrayList<Prop> list = property(name.toLowerCase());
		if (list == null)
			return dflt;
		for (Prop p : list)
			if (p.type == Prop.FLOAT)
				scale = (float)(Float)p.value;
			else if (p.type == Prop.COLOR)
				ret = (ColorRGBA)p.value;
		return new ColorRGBA(ret.r*scale, ret.g*scale, ret.b*scale, ret.a*scale);
	}

	public TextureMap propertyTexture(String name, TextureMap dflt) {
		ArrayList<Prop> list = property(name.toLowerCase());
		if (list == null)
			return dflt;
		for (Prop p : list)
			if (p.type == Prop.TEXTURE)
				return (TextureMap)p.value;
		return dflt;
	}

	public boolean hasOpacity() {
		ArrayList<Prop> list = property(OPACITY);
		if (list == null)
			return false;
		for (Prop p : list) {
			if (p.type == Prop.FLOAT)
				if ((float)(Float)p.value < 1)
					return true;
			if (p.type == Prop.COLOR)
				if (((ColorRGBA)p.value).a < 1)
					return true;
			if (p.type == Prop.TEXTURE)
				return true;
		}
		return false;
	}

	public void addProperty(String name, String id, float v) throws Exception {
		name = name.toLowerCase();
		Prop p = new Prop(name, (Float)v);
		getOrMakeProp(name).add(p);
		if (id != null)
			propsById.put(id, p);
	}

	public void addProperty(String name, String id, ColorRGBA v) throws Exception {
		if (v == null)
			throw new Exception("addProperty() on a null color");
		name = name.toLowerCase();
		Prop p = new Prop(name, v);
		getOrMakeProp(name).add(p);
		if (id != null)
			propsById.put(id, p);
	}

	public void addProperty(String name, String id, TextureMap v) throws Exception {
		if (v == null)
			throw new Exception("addProperty() on a null texture");
		name = name.toLowerCase();
		Prop p = new Prop(name, v);
		getOrMakeProp(name).add(p);
		if (id != null)
			propsById.put(id, p);
	}

	ArrayList<Prop> getOrMakeProp(String name) {
		ArrayList<Prop> ret = props.get(name.toLowerCase());
		if (ret == null) {
			ret = new ArrayList<Prop>();
			props.put(name.toLowerCase(), ret);
		}
		return ret;
	}

	public final static String EMISSIVE = "emissive";
	public final static String DIFFUSE = "diffuse";
	public final static String AMBIENT = "ambient";
	public final static String SPECULAR = "specular";
	public final static String POWER = "power";
	public final static String OPACITY = "opacity";
	public final static String REFLECTION = "reflection";
}

